要真正理解 Logits、Softmax 和 Temperature,先得知道 它们在大模型里到底住在哪一层。这一章从大模型(以 GPT、LLaMA、Qwen 等为代表)的 整体架构 出发,定位 Logits 的"出生地"。
大语言模型(LLM)的本质是 N 层 Transformer Block 的堆叠。每一层 Block 都包含两个核心子模块:多头注意力(MHA) 和 前馈网络(FFN),再加上残差连接和 LayerNorm。
每个 Block 由两部分组成:
经过 N 层 Transformer Block 之后,模型得到一个 高维隐藏向量(如 4096 维或 8192 维)。这个向量浓缩了"当前语境下,下一个 Token 应该长什么样"的全部信息。
最后一步:LM Head(输出层)将这个向量通过一个 线性映射(无激活函数),投影到 词表大小 的维度(如 50000 或 128000),得到的就是 Logits。
# 假设 hidden_size=4096, vocab_size=50000 lm_head = nn.Linear(4096, 50000, bias=False) # hidden 是 Transformer 最后一层的输出 (batch, seq, 4096) logits = lm_head(hidden) # → (batch, seq, 50000) # 然后除以 Temperature,过 Softmax,采样得到下一个 Token logits = logits / temperature probs = softmax(logits) next_token = sample(probs)
总结这一章:大模型 = N 层 Transformer Block 堆叠 → 最后一层的隐藏向量过一个线性层 → 得到 Logits → 除以 Temperature → Softmax → 概率 → 采样。Logits 是整个流程的"第一站",后续的 Softmax 和 Temperature 都是对它的加工。
我们总说 AI 输出「80% 是猫,20% 是狗」—— 但 在模型内部,它从来不会直接算概率。因为概率必须乖乖待在 0 到 1 之间,而神经网络天生是个「暴躁的算术家」,内部全是矩阵乘法,动辄算出 几千 或 负数。
如果强行让每一层神经元都「守规矩」,结果必须卡在 0~1 之间,那就像让短跑运动员裹着棉被跑步 —— 又慢又使不出全力(梯度消失,模型学不动)。
简单说:模型靠「误差反向传播」来学习,如果中间某一步的导数(变化率)接近 0,那前面的层就收不到有效的学习信号,相当于 教了半天,前排学生全睡着了。而 Logits 是线性运算,它的导数是常数 1,信号可以畅通无阻地传回每一层。
# 假设我们硬把输出限制在 [0,1] def clamped_forward(x): return max(0, min(1, x)) # 强行截断 # 当 x > 1 或 x < 0 时,导数为 0 → 梯度消失! # 而 Logits 直接输出 x,导数为 1 → 学习信号满格 💪
Logits 就是神经网络在最后一层算出来的 原始分数,它可以是 正数、负数、大数 或 小数,完全没有限制。模型在 Logits 空间里 随便撒欢,想打多少分就打多少分。
在二分类场景下,Logits 确实来源于 「对数几率」(Log Odds):如果某件事发生的概率是 p,那么胜算比 Odds = p/(1-p),取自然对数后就是 ln(p/(1-p)),范围从 负无穷 到 正无穷。这正好把概率空间「展开」成了整个实数轴,模型可以自由翱翔。
假设猫的概率 p = 0.8,那么 Odds = 0.8/0.2 = 4,Logits = ln(4) ≈ 1.386。如果 p = 0.99,Odds = 99,Logits ≈ 4.595。可见,越接近 1,Logits 就越大,模型就越「自信」。反过来 p = 0.1,Logits ≈ −2.197,表示模型觉得这事儿不靠谱。
import math def prob_to_logits(p): # 将概率 p 转换为 Logits(对数几率) if p <= 0 or p >= 1: raise ValueError("p 必须在 (0,1) 之间") return math.log(p / (1 - p)) print(prob_to_logits(0.8)) # 输出 ≈ 1.386 print(prob_to_logits(0.99)) # 输出 ≈ 4.595 print(prob_to_logits(0.1)) # 输出 ≈ −2.197
模型打了一堆 Logits 裸分,比如针对「猫 / 狗 / 车」打出了 [2.0, 1.0, 0.0]。怎么把这些乱七八糟的分数变成 加起来刚好等于 100% 的靠谱概率? Softmax 就是那个「操盘手」,它分三步走:
因为指数函数 e^x 有两个绝佳特性:
import numpy as np def softmax(logits): # 输入: logits 列表或数组 # 输出: 概率分布,总和为 1 exp_vals = np.exp(logits) # 取指数 sum_exp = np.sum(exp_vals) # 求和 return exp_vals / sum_exp # 归一化 logits = [2.0, 1.0, 0.0] probs = softmax(logits) print(probs) # 输出: [0.665, 0.245, 0.090] print(sum(probs)) # 输出: 1.0
在把 Logits 扔进 Softmax 之前,我们可以先除以一个 温度 T。这个 T 就像 AI 的 「胆量调节旋钮」,直接控制着模型是「死磕最优解」还是「天马行空」。
假设 Logits = [10, 9, 8]:
import numpy as np def softmax_with_temp(logits, temperature): scaled = np.array(logits) / temperature exp_vals = np.exp(scaled) return exp_vals / np.sum(exp_vals) logits = [10, 9, 8] print(softmax_with_temp(logits, 0.5)) # 尖锐 print(softmax_with_temp(logits, 1.0)) # 正常 print(softmax_with_temp(logits, 10.0)) # 平坦
Softmax 算出的只是概率分布,比如「猫 60%,狗 40%」。但模型 并不总是直接选概率最大的(那叫「贪心解码」)。实际中,模型会把这个概率分布做成一个 「抽签转盘」,然后随机拨动指针。
这就是为什么问同一个问题两次,答案可能不一样! 因为转盘每次停的位置可能不同。Temperature 越高,转盘上各扇区面积越接近,抽中冷门选项的概率越大;Temperature 越低,最大扇区几乎占满整个转盘,结果就变得死板且确定。
实际代码中,我们使用 多项式分布(Multinomial Distribution)或 torch.multinomial 来实现采样。核心逻辑就是:按照概率大小,给每个选项分配一个「区间」,然后扔一个 0~1 的随机数,看落在哪个区间里。
import numpy as np def sample_from_probs(probs): cumsum = np.cumsum(probs) # 累积分布 [0.6, 1.0] r = np.random.rand() # 生成 0~1 随机数 for i, threshold in enumerate(cumsum): if r < threshold: return i # 返回选中的索引 return len(probs) - 1 probs = [0.6, 0.4] # 猫 60%, 狗 40% print(sample_from_probs(probs)) # 可能是 0(猫)或 1(狗)
在 Transformer 架构(比如 GPT 系列)里,Logits 是怎么算出来的?其实最后一步非常简单:
可以理解为:模型把「当前语境」浓缩成一个「灵魂向量」,然后去跟词表里的每一个单词「做点积」(算相似度),得到的相似度分数就是 Logits。哪个词跟当前语境最像,它的 Logits 分就最高。
在 PyTorch 中,这通常就是 nn.Linear(hidden_size, vocab_size) 一层搞定。不需要任何激活函数,直接输出原始分数。
import torch import torch.nn as nn linear_layer = nn.Linear(4096, 50000, bias=True) hidden = torch.randn(1, 1, 4096) # 模拟 Transformer 输出 logits = linear_layer(hidden) # 形状: (1, 1, 50000) print(logits.shape) # torch.Size([1, 1, 50000])
Logits 是模型的「原始裸分」—— 任意实数,自由奔放。
Softmax 是「分蛋糕机器」—— 把裸分变成概率,总和 1,每个 > 0。
Temperature 是「胆量旋钮」—— 调低变保守,调高变创造。
记住这句话: 概率是给人类看的,Logits 才是模型真正「爱」的。而 Temperature 和采样,则决定了这个模型是 「严肃的专家」 还是 「天马行空的诗人」。